/*
 * TheGame.cpp
 *
 *  Created on: 14 déc. 2011
 *      Author: M. Alexandre (malexand314@gmail.com)
 */

#include "TheGame.h"

#include "../Framework/Misc.h"
#include <ctime>

TheGame::TheGame() : Framework::Observer()
{
    m_bIsGameFinished = false;
    m_bIsGameWon = false;

    m_timer.attachObserver(this);
}

TheGame::~TheGame()
{

}

void TheGame::update(Framework::ObserverSubject* _ptSubject)
{
    if(_ptSubject == &m_timer)
    {
        localPoolPush(((Framework::Timer*)_ptSubject)->getTimeRemaining());
    }
}

void TheGame::initIntegerAvailable()
{
    m_vecIntegerAvailable.clear();

    m_vecIntegerAvailable.push_back(1);
    m_vecIntegerAvailable.push_back(1);
    m_vecIntegerAvailable.push_back(2);
    m_vecIntegerAvailable.push_back(2);
    m_vecIntegerAvailable.push_back(3);
    m_vecIntegerAvailable.push_back(3);
    m_vecIntegerAvailable.push_back(4);
    m_vecIntegerAvailable.push_back(4);
    m_vecIntegerAvailable.push_back(5);
    m_vecIntegerAvailable.push_back(5);
    m_vecIntegerAvailable.push_back(6);
    m_vecIntegerAvailable.push_back(6);
    m_vecIntegerAvailable.push_back(7);
    m_vecIntegerAvailable.push_back(7);
    m_vecIntegerAvailable.push_back(8);
    m_vecIntegerAvailable.push_back(8);
    m_vecIntegerAvailable.push_back(9);
    m_vecIntegerAvailable.push_back(9);
    m_vecIntegerAvailable.push_back(10);
    m_vecIntegerAvailable.push_back(10);
    m_vecIntegerAvailable.push_back(25);
    m_vecIntegerAvailable.push_back(50);
    m_vecIntegerAvailable.push_back(75);
    m_vecIntegerAvailable.push_back(100);
}

T_GameSet TheGame::generateAndGetNumbers()
{
    generateNumbers();
    m_timer.startTimer(45);
    return m_gameSet;
}

void TheGame::generateNumbers()
{
    initIntegerAvailable();
    m_vecCurrentlyAvailable.clear();

    for(int i = 0; i < 6; i++)
    {
        int iRandomInt = Framework::Misc::randomInt(0, m_vecIntegerAvailable.size());
        m_gameSet.aiTab[i] = m_vecIntegerAvailable[iRandomInt];
        m_vecCurrentlyAvailable.push_back(m_vecIntegerAvailable[iRandomInt]);
        m_vecIntegerAvailable.erase(m_vecIntegerAvailable.begin() + iRandomInt);
    }

    m_gameSet.iResult = Framework::Misc::randomInt(100, 999);

    m_bIsGameFinished = false;
    m_bIsGameWon = false;
}

T_GameState TheGame::localPoolPop()
{
    return m_pool.pop();
}

void TheGame::localPoolPush(int _iTimeRemaining)
{
    T_GameState gameState;

    gameState.iTimeRemaining = _iTimeRemaining;
    gameState.bIsGameFinished = (m_bIsGameFinished || _iTimeRemaining <= 0);
    gameState.bIsGameWon = m_bIsGameWon;

    m_bIsGameFinished = gameState.bIsGameFinished;

    m_pool.push(gameState);
}

bool TheGame::isPoolDataAvailable()
{
    int iPoolSize = m_pool.size();
    return (iPoolSize > 0);
}

bool TheGame::addOperation(const T_Operation& _operation)
{
    bool bReturn = false;

    if(!m_bIsGameFinished)
    {
        int iIdxA = Framework::Misc::linearIntSearch(m_vecCurrentlyAvailable, _operation.iA);
        int iIdxB = Framework::Misc::linearReverseIntSearch(m_vecCurrentlyAvailable, _operation.iB);

        if(iIdxA != -1 && iIdxB != -1)
        {
            int iResult = Solver::getResultForOperation(_operation);
            if(iResult != -1)
            {
                m_vecCurrentlyAvailable[iIdxA] = iResult;
                m_vecCurrentlyAvailable.erase(m_vecCurrentlyAvailable.begin() + iIdxB);

                if(iResult == m_gameSet.iResult)
                {
                    m_bIsGameFinished = true;
                    m_bIsGameWon = true;

                    m_timer.stopTimer();
                    localPoolPush(0);
                }

                bReturn = true;
            }
        }

        if(bReturn == false)
        {
            std::cout << "You cheater ! (" << _operation.iA << ", " << _operation.iB << ", " << _operation.cOperation << ")" << std::endl;
        }
    }

    return bReturn;
}

bool TheGame::delOperation(const T_Operation& _operation)
{
    bool bReturn = false;

    if(!m_bIsGameFinished)
    {
        int iResult = Solver::getResultForOperation(_operation);

        if(iResult != -1)
        {
            int iIdxResult = Framework::Misc::linearIntSearch(m_vecCurrentlyAvailable, iResult);

            if(iIdxResult != -1)
            {
                m_vecCurrentlyAvailable.erase(m_vecCurrentlyAvailable.begin() + iIdxResult);
                m_vecCurrentlyAvailable.push_back(_operation.iA);
                m_vecCurrentlyAvailable.push_back(_operation.iB);

                bReturn = true;
            }
        }
    }

    return bReturn;
}

void TheGame::findFirstPossibleSolution()
{
    std::vector<int> vecToSolve;
    for(int i = 0; i < 6; i++)
    {
        vecToSolve.push_back(m_gameSet.aiTab[i]);
    }

    T_Solution solution;
    solution.iMaxValue = 0;

    if(!Solver::findFirstPossibleSolution(vecToSolve, m_gameSet.iResult, &solution))
    {
        std::cout << "No solution found !" << std::endl;
    }
    else
    {
        std::cout << "Solution :" << std::endl;
        for(int i = (int) solution.vecSolution.size() - 1; i >= 0; i--)
        {
            std::cout << "\t" << Solver::getStringForOperation(solution.vecSolution[i]) << std::endl;
        }
    }
}

void TheGame::findAllSolution()
{

}
